package com.fengye.revoker;

import com.fengye.common.IPHelper;
import com.fengye.model.InvokeService;
import com.fengye.model.ProviderService;
import com.fengye.register.RegisterCenter;
import com.fengye.register.RegisterCenter4Invoker;
import org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;

import java.util.List;
import java.util.Map;

/**
 * @Author fengye
 * @Date 2023/2/14 14:21
 **/
public class RevokerFactoryBean implements FactoryBean, InitializingBean {

    private final static Logger logger = LoggerFactory.getLogger(RevokerFactoryBean.class);

    /** 服务接口 */
    private Class<?> targetInterface;
    /** 超时时间 */
    private int timeout;
    /** 服务bean */
    private Object serviceObject;
    /** 负载均衡策略（这个放在调用端？） */
    private String clusterStrategy;
    /** 服务提供者唯一标识 */
    private String remoteAppKey;

    /** 服务调用方唯一标识 */
    private String appKey;
    /** 服务分组 */
    private String groupName = "default";

    @Override
    public Object getObject() throws Exception {
        return serviceObject;
    }

    @Override
    public Class<?> getObjectType() {
        return targetInterface;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        // 获取服务注册中心
        RegisterCenter4Invoker registerCenter4Invoker = RegisterCenter.singleton();
        // 订阅服务提供者列表到本地缓存
        String serviceName = targetInterface.getName();
        registerCenter4Invoker.subscribe(serviceName, remoteAppKey, groupName);

        Map<String, List<ProviderService>> providerMap = registerCenter4Invoker.getServiceMetaDataMap4Consume();
        if(MapUtils.isEmpty(providerMap)) {
            logger.error("remoteAppKey: " + remoteAppKey + ", groupName: " + groupName
                    + " service provider list is empty.");
            throw new RuntimeException("remoteAppKey: " + remoteAppKey + ", groupName: " + groupName
                    + " service provider list is empty");
        }
        // 根据服务提供者信息创建Netty channel Pool Factory
        NettyChannelPoolFactory.channelPoolFactoryInstance().initChannelPoolFactory(providerMap);

        // 获取服务提供者代理对象
        RevokerProxyBeanFactory proxyBeanFactory = RevokerProxyBeanFactory.getSingleton(targetInterface, timeout, appKey, clusterStrategy);
        this.serviceObject = proxyBeanFactory.getProxy();

        InvokeService invokeService = new InvokeService();
        invokeService.setServiceItf(targetInterface);
//        invokeService.setServiceObject(serviceObject);
        invokeService.setRemoteAppKey(remoteAppKey);
        invokeService.setGroupName(groupName);
        invokeService.setAppKey(appKey);
        invokeService.setTimeout(timeout);
        invokeService.setInvokerIp(IPHelper.localIp());
        registerCenter4Invoker.registerInvoker(invokeService);
    }

    public Class<?> getTargetInterface() {
        return targetInterface;
    }

    public void setTargetInterface(Class<?> targetInterface) {
        this.targetInterface = targetInterface;
    }

    public int getTimeout() {
        return timeout;
    }

    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    public Object getServiceObject() {
        return serviceObject;
    }

    public void setServiceObject(Object serviceObject) {
        this.serviceObject = serviceObject;
    }

    public String getClusterStrategy() {
        return clusterStrategy;
    }

    public void setClusterStrategy(String clusterStrategy) {
        this.clusterStrategy = clusterStrategy;
    }

    public String getRemoteAppKey() {
        return remoteAppKey;
    }

    public void setRemoteAppKey(String remoteAppKey) {
        this.remoteAppKey = remoteAppKey;
    }

    public String getAppKey() {
        return appKey;
    }

    public void setAppKey(String appKey) {
        this.appKey = appKey;
    }

    public String getGroupName() {
        return groupName;
    }

    public void setGroupName(String groupName) {
        this.groupName = groupName;
    }
}
